package org.luxor.commons.core.utils;


import org.luxor.commons.core.exception.BaseException;
import org.luxor.commons.core.utils.encrypt.Md5EncryptUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import javax.xml.bind.DatatypeConverter;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;
import java.util.TreeMap;

/**
 * 接口签名工具类
 *
 * @author Mr.Yan  @date: 2022/5/18
 */
public class Sign {
    private static final Logger logger = LoggerFactory.getLogger(Sign.class);

    /**
     * 可允许的时间误差范围(5分钟)
     */
    public static final long TIMESTAMP_TIMEOUT_MS = 300000;

    public static final String SIG_METHOD = "HmacSHA256";
    public static final String SIGNATURE = "signature";
    public static final String CLIENT_ID = "clientId";
    public static final String TIMESTAMP = "timestamp";
    public static final String NONCE = "nonce";

    /**
     * 签名
     *
     * @param secretKey     秘钥KEY
     * @param signPlainText 签名内容
     * @param sigMethod     签名算法
     * @return java.lang.String
     */
    public static String sign(String secretKey, String signPlainText, String sigMethod)
            throws BaseException {
        String sign;
        try {
            Mac mac = Mac.getInstance(sigMethod);
            byte[] hash;
            SecretKeySpec secretKeySpec = new SecretKeySpec(secretKey.getBytes(StandardCharsets.UTF_8), mac.getAlgorithm());
            mac.init(secretKeySpec);
            hash = mac.doFinal(signPlainText.getBytes(StandardCharsets.UTF_8));
            sign = DatatypeConverter.printBase64Binary(hash);
        } catch (Exception e) {
            throw new BaseException(e.getClass().getName() + "-" + e.getMessage());
        }
        return sign;
    }

    /**
     * 将http请求内容转换为纯文本
     * <p/>
     * ?paramName1=paramValue1&paramName2=paramValue2&name=颜新明#body=289DFF07669D7A23DE0EF88D2F7129E7{clientSecret}
     *
     * @param clientSecret  客户端秘钥
     * @param requestParams 请求参数
     * @param requestBody   请求报文
     */
    public static String makeSignPlainText(String clientSecret, TreeMap<String, String> requestParams, byte[] requestBody) throws UnsupportedEncodingException {
        if (requestBody == null || requestBody.length == 0) {
            requestBody = "".getBytes();
        }
        StringBuffer retStr = new StringBuffer();
        retStr.append(buildParamStr(requestParams))
                .append("#body=").append(Md5EncryptUtils.md5(requestBody))
                .append("{").append(clientSecret).append("}");
        if (logger.isDebugEnabled()) {
            logger.debug("makeSignPlainText:" + retStr);
        }
        return retStr.toString();
    }

    protected static String buildParamStr(TreeMap<String, String> requestParams) throws UnsupportedEncodingException {
        String retStr = "";
        for (String name : requestParams.keySet()) {
            String value = requestParams.get(name);
            if (SIGNATURE.equals(name) || name == null || name.trim().length() == 0 || value == null || value.trim().length() == 0) {
                continue;
            }
            if (retStr.length() == 0) {
                retStr += "?";
            } else {
                retStr += "&";
            }
            retStr += name + "=" + URLDecoder.decode("" + value, StandardCharsets.UTF_8.name());
        }
        return retStr;
    }

}
